package es.goalproject.core.dao;

import java.io.Serializable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.Query;

import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Create;
import org.jboss.seam.annotations.Destroy;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Logger;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.log.Log;
import org.jboss.seam.persistence.HibernateSessionProxy;

import es.goalproject.core.dominio.AbstractBase;


@Name("abstractBaseDAO")
@Scope(ScopeType.CONVERSATION)
public class AbstractBaseDAO implements Serializable {

	/**
     *
     */
	private static final long serialVersionUID = -1198300544827580561L;

	@Logger
	Log log;

	@In(create = true)
	private EntityManager em;

	@Create
	public void create() {
		if (log.isDebugEnabled()) {
			log.debug("create init");
		}
		if (log.isDebugEnabled()) {
			log.debug("create end");
		}
	}

	public void updateList(List<AbstractBase> list) {
		if (log.isDebugEnabled()) {
			log.debug("UpdateList size: " + list.size() + " values.");
		}
		for (AbstractBase baseDTO : list) {
			update(baseDTO);
		}
		if (log.isDebugEnabled()) {
			log.debug("UpdateList done successfully.");
		}
	}

	public void updateSet(Set<AbstractBase> list) {
		if (log.isDebugEnabled()) {
			log.debug("UpdateSet size: " + list.size() + " values.");
		}
		for (AbstractBase baseDTO : list) {
			update(baseDTO);
		}
		if (log.isDebugEnabled()) {
			log.debug("UpdateSet done successfully.");
		}
	}

	public void insertOrUpdateList(List<AbstractBase> list) {
		if (log.isDebugEnabled()) {
			log.debug("InsertOrUpdateList size: " + list.size() + " values.");
		}
		for (AbstractBase baseDTO : list) {
			insertOrUpdate(baseDTO);
		}
		if (log.isDebugEnabled()) {
			log.debug("InsertOrUpdateList done successfully.");
		}
	}

	public void insertOrUpdateSet(Set<AbstractBase> list) {
		if (log.isDebugEnabled()) {
			log.debug("InsertOrUpdateSet size: " + list.size() + " values.");
		}
		for (AbstractBase baseDTO : list) {
			insertOrUpdate(baseDTO);
		}
		if (log.isDebugEnabled()) {
			log.debug("InsertOrUpdateSet done successfully.");
		}
	}

	public void update(AbstractBase baseDTO) {
		if (log.isDebugEnabled()) {
			log.debug("Update element: " + baseDTO.getClass() + " (PrimaryKey = "
				+ baseDTO.getPrimaryKey() + " )");
		}
		em.merge(baseDTO);
		em.flush();
		if (log.isDebugEnabled()) {
			log.debug("Update done successfully.");
		}
	}

	public void insertOrUpdate(AbstractBase baseDTO) {
		if (log.isDebugEnabled()) {
			log.debug("InsertOrUpdate element: "
				+ baseDTO.getClass()
				+ " (PrimaryKey = "
				+ (baseDTO.getPrimaryKey() == null ? "NEW" : baseDTO
						.getPrimaryKey()) + " )");
		}
		if (baseDTO.getPrimaryKey() == null) {
			em.persist(baseDTO);
			em.flush();
		} else {
			em.merge(baseDTO);
			em.flush();
		}
		if (log.isDebugEnabled()) {
			log.debug("InsertOrUpdate done successfully.");
		}
	}

	@SuppressWarnings("unchecked")
	public List<AbstractBase> queryListMoreParameters(String namedQuery,
			Map<String, Object> parameters) {
		List<AbstractBase> list;
		if (log.isDebugEnabled()) {
			log.debug("QueryList: " + namedQuery);
		}

		Query query = em.createNamedQuery(namedQuery);

		if (parameters != null && !parameters.isEmpty()) {
			if (log.isDebugEnabled()) {
				log.debug("Query with parameters: " + parameters.size());
			}
			Iterator itParameter = parameters.keySet().iterator();
			while (itParameter.hasNext()) {
				String parameterName = (String) itParameter.next();
				Object parameterValue = parameters.get(parameterName);
				query.setParameter(parameterName, parameterValue);
				if (log.isDebugEnabled()) {
					log.debug("Parameter name: " + parameterName + " value: "
							+ parameterValue);
				}
			}
		}
		list = query.getResultList();
		if (log.isDebugEnabled()) {
			log.debug("QueryList obtains: " + list.size() + " values.");
		}

		return list;
	}

	@SuppressWarnings("unchecked")
	public Integer integerValue(String namedQuery) {
		if (log.isDebugEnabled()) {
			log.debug("QueryList: " + namedQuery);
		}

		Query query = em.createNamedQuery(namedQuery);

		Integer value = (Integer) query.getSingleResult();

		return value;
	}

	@SuppressWarnings("unchecked")
	public List<AbstractBase> queryListMoreParametersList(String namedQuery,
			Map<String, Object[]> parameters) {
		List<AbstractBase> list;
		if (log.isDebugEnabled()) {
			log.debug("QueryList: " + namedQuery);
		}

		org.hibernate.Query query = ((HibernateSessionProxy) em.getDelegate())
				.getNamedQuery(namedQuery);

		if (parameters != null && !parameters.isEmpty()) {
			if (log.isDebugEnabled()) {
				log.debug("Query with parameters: " + parameters.size());
			}
			Iterator itParameter = parameters.keySet().iterator();
			while (itParameter.hasNext()) {
				String parameterName = (String) itParameter.next();
				Object[] parameterValue = parameters.get(parameterName);
				query.setParameterList(parameterName, parameterValue);
				if (log.isDebugEnabled()) {
					log.debug("Parameter name: " + parameterName + " value: "
							+ parameterValue);
				}
			}
		}

		list = query.list();
		if (log.isDebugEnabled()) {
			log.debug("QueryList obtains: " + list.size() + " values.");
		}

		return list;
	}

	public AbstractBase queryElementMoreParametersWithOutLog(
			String namedQuery, Map<String, Object> parameters) {
		AbstractBase result = null;
		if (log.isDebugEnabled()) {
			log.debug("QueryElement: " + namedQuery);
		}

		Query query = em.createNamedQuery(namedQuery);

		if (parameters != null && !parameters.isEmpty()) {
			if (log.isDebugEnabled()) {
				log.debug("Query with parameters: " + parameters.size());
			}
			Iterator<String> itParameter = parameters.keySet().iterator();
			while (itParameter.hasNext()) {
				String parameterName = itParameter.next();
				Object parameterValue = parameters.get(parameterName);
				query.setParameter(parameterName, parameterValue);
			}
		}
		try {
			result = (AbstractBase) query.getSingleResult();
		} catch (NoResultException e) {
			if (log.isDebugEnabled()) {
				log.debug("No result found");
			}
		}
		if (log.isDebugEnabled()) {
			log.debug("QueryElement obtains: " + (result == null ? "0" : "1")
					+ " values.");
		}

		return result;
	}

	@SuppressWarnings("unchecked")
	public List<AbstractBase> queryListOneParameter(String namedQuery,
			String parameterName, Object parameterValue) {
		List<AbstractBase> list;

		if (log.isDebugEnabled()) {
			log.debug("QueryList: " + namedQuery);
		}

		Query query = em.createNamedQuery(namedQuery);

		if (parameterName != null) {
			query.setParameter(parameterName, parameterValue);
		}

		if (log.isDebugEnabled()) {
			log.debug("Parameter name: " + parameterName + " value: "
					+ parameterValue);
		}

		list = query.getResultList();
		if (log.isDebugEnabled()) {
			log.debug("QueryList obtains: " + list.size() + " values.");
		}

		return list;
	}

	@SuppressWarnings("unchecked")
	public List<AbstractBase> queryListOneParameterList(String namedQuery,
			String parameterName, Object[] parameterValues) {
		List<AbstractBase> list;

		if (log.isDebugEnabled()) {
			log.debug("QueryList: " + namedQuery);
		}

		org.hibernate.Query query = ((HibernateSessionProxy) em.getDelegate())
				.getNamedQuery(namedQuery);

		if (parameterName != null) {
			query.setParameterList(parameterName, parameterValues);
		}
		if (log.isDebugEnabled()) {
			log.debug("Parameter name: " + parameterName + " value: "
					+ parameterValues);
		}

		list = query.list();
		if (log.isDebugEnabled()) {
			log.debug("QueryList obtains: " + list.size() + " values.");
		}

		return list;
	}

	/** Method for massive updates. */
	public void massiveUpdate(String namedQuery, String parameterName,
			Object parameterValue) {
		if (log.isDebugEnabled()) {
			log.debug("QueryList: " + namedQuery);
		}

		Query query = em.createNamedQuery(namedQuery);

		if (parameterName != null) {
			query.setParameter(parameterName, parameterValue);
		}
		if (log.isDebugEnabled()) {
			log.debug("Parameter name: " + parameterName + " value: "
					+ parameterValue);
		}

		query.executeUpdate();
	}

	@SuppressWarnings("unchecked")
	public List<AbstractBase> queryListMoreParametersListComplex(
			String namedQuery, Map<String, Object[]> parametersList,
			Map<String, Object> parametersSimple) {
		List<AbstractBase> list;

		if (log.isDebugEnabled()) {
			log.debug("QueryList: " + namedQuery);
		}

		org.hibernate.Query query = ((HibernateSessionProxy) em.getDelegate())
				.getNamedQuery(namedQuery);

		if (parametersList != null && !parametersList.isEmpty()) {
			if (log.isDebugEnabled()) {
				log.debug("Query with parameters: " + parametersList.size());
			}
			Iterator itParameter = parametersList.keySet().iterator();
			while (itParameter.hasNext()) {
				String parameterName = (String) itParameter.next();
				Object[] parameterValue = parametersList.get(parameterName);
				query.setParameterList(parameterName, parameterValue);
				if (log.isDebugEnabled()) {
					log.debug("Parameter name: " + parameterName + " value: "
							+ parameterValue);
				}
			}
		}

		if (parametersSimple != null && !parametersSimple.isEmpty()) {
			if (log.isDebugEnabled()) {
				log.debug("Query with parameters: " + parametersSimple.size());
			}
			Iterator itParameter = parametersSimple.keySet().iterator();
			while (itParameter.hasNext()) {
				String parameterName = (String) itParameter.next();
				Object parameterValue = parametersSimple.get(parameterName);
				query.setParameter(parameterName, parameterValue);
				if (log.isDebugEnabled()) {
					log.debug("Parameter name: " + parameterName + " value: "
							+ parameterValue);
				}
			}
		}

		list = query.list();
		if (log.isDebugEnabled()) {
			log.debug("QueryList obtains: " + list.size() + " values.");
		}

		return list;
	}

	public void deleteList(List<AbstractBase> list) {
		if (log.isDebugEnabled()) {
			log.debug("DeleteList size: " + list.size() + " values.");
		}
		for (AbstractBase baseDTO : list) {
			delete(baseDTO);
		}
		if (log.isDebugEnabled()) {
			log.debug("DeleteList done successfully.");
		}
	}

	public void delete(AbstractBase baseDTO) {
		if (log.isDebugEnabled()) {
			log.debug("Delete element: " + baseDTO.getClass() + " (PrimaryKey = "
					+ baseDTO.getPrimaryKey() + " )");
		}
		// em.remove(em.merge(baseDTO));
		em.remove(em.find(baseDTO.getClass(), baseDTO.getPrimaryKey()));
		if (log.isDebugEnabled()) {
			log.debug("Delete done successfully.");
		}
	}

	public AbstractBase queryElementMoreParameters(String namedQuery,
			Map<String, Object> parameters) {
		AbstractBase result = null;
		if (log.isDebugEnabled()) {
			log.debug("QueryElement: " + namedQuery);
		}

		Query query = em.createNamedQuery(namedQuery);

		if (parameters != null && !parameters.isEmpty()) {
			log.debug("Query with parameters: " + parameters.size());
			Iterator<String> itParameter = parameters.keySet().iterator();
			while (itParameter.hasNext()) {
				String parameterName = itParameter.next();
				Object parameterValue = parameters.get(parameterName);
				query.setParameter(parameterName, parameterValue);
				if (log.isDebugEnabled()) {
					log.debug("Parameter name: " + parameterName + " value: "
							+ parameterValue);
				}
			}
		}
		try {
			result = (AbstractBase) query.getSingleResult();
		} catch (NoResultException e) {
			log.debug("No result found");
		}
		if (log.isDebugEnabled()) {
			log.debug("QueryElement obtains: " + (result == null ? "0" : "1")
					+ " values.");
		}

		return result;
	}

	public AbstractBase queryElementOneParameter(String namedQuery,
			String parameterName, Object parameterValue) {
		AbstractBase result = null;
		if (log.isDebugEnabled()) {
			log.debug("QueryElement: " + namedQuery);
		}

		Query query = em.createNamedQuery(namedQuery);

		if (parameterName != null) {
			query.setParameter(parameterName, parameterValue);
		}
		if (log.isDebugEnabled()) {
			log.debug("Parameter name: " + parameterName + " value: "
					+ parameterValue);
		}

		try {
			result = (AbstractBase) query.getSingleResult();
		} catch (NoResultException e) {
			if (log.isDebugEnabled()) {
				log.debug("No result found");
			}
		}
		if (log.isDebugEnabled()) {
			log.debug("QueryElement obtains: " + (result == null ? "0" : "1")
					+ " values.");
		}

		return result;
	}

	public Long queryCount(String namedQuery, Map<String, Object> parameters) {
		Long result;
		if (log.isDebugEnabled()) {
			log.debug("QueryCount: " + namedQuery);
		}

		Query query = em.createNamedQuery(namedQuery);

		if (parameters != null && !parameters.isEmpty()) {
			if (log.isDebugEnabled()) {
				log.debug("Query with parameters: " + parameters.size());
			}
			Iterator<String> itParameter = parameters.keySet().iterator();
			while (itParameter.hasNext()) {
				String parameterName = itParameter.next();
				Object parameterValue = parameters.get(parameterName);
				query.setParameter(parameterName, parameterValue);
				if (log.isDebugEnabled()) {
					log.debug("Parameter name: " + parameterName + " value: "
							+ parameterValue);
				}
			}
		}

		result = (Long) query.getSingleResult();
		if (log.isDebugEnabled()) {
			log.debug("QueryCount obtains: " + result.intValue() + " values.");
		}

		return result;
	}

	public void executePLSQL(String PLSQL) {
		if (log.isDebugEnabled()) {
			log.debug("executePLSQL: " + PLSQL);
		}
		em.getTransaction().begin();
		Query query = em.createNativeQuery(PLSQL);
		query.executeUpdate();
		em.getTransaction().commit();
	}

	public void insertOrUpdateCommit(AbstractBase baseDTO) {
		em.getTransaction().begin();
		insertOrUpdate(baseDTO);
		em.getTransaction().commit();
	}

	public void refresh(AbstractBase baseDTO) {
		em.merge(baseDTO);
	}

	@Destroy
	public void destroy() {
		if (log.isDebugEnabled()) {
			log.debug("BaseDAO destroyed.");
		}
	}

	public EntityManager getEntityManager() {
		return em;
	}

	public void setEntityManager(EntityManager em) {
		this.em = em;
	}

}
